/*
 *
 *      Copyright (c) 2018-2025, edu All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *
 * Redistributions of source code must retain the above copyright notice,
 *  this list of conditions and the following disclaimer.
 *  Redistributions in binary form must reproduce the above copyright
 *  notice, this list of conditions and the following disclaimer in the
 *  documentation and/or other materials provided with the distribution.
 *  Neither the name of the glng.net developer nor the names of its
 *  contributors may be used to endorse or promote products derived from
 *  this software without specific prior written permission.
 *  Author: glng
 *
 */

package com.zhang.zxx.boot.common.core;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import java.util.Objects;
import java.util.Optional;

/**
 * SpringContextHolder:SpringContext上下文处理器[可以理解为一个工具类]
 *
 * @author zhangxiaoxiang
 * @date 2021年11月27日
 */
@Slf4j
@Service
@Lazy(false)
public class SpringContextHolder implements ApplicationContextAware, DisposableBean {

    private static ApplicationContext applicationContext = null;
    private static boolean isDebug;
    private static Integer serverPort = -1;
    /**
     * 当前激活的环境 dev-test-prod
     */
    @Value("${spring.profiles.active: prop}")
    private String profiles;

    /**
     * 是否是调试环境
     *
     * @return 是否是调试环境
     */
    public static Boolean isDebug() {
        return isDebug;
    }

    /**
     * 获取项目启动端口
     *
     * @return 项目启动端口
     */
    public static Integer getServerPort() {
        return serverPort;
    }

    /**
     * 取得存储在静态变量中的ApplicationContext.
     */
    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    /**
     * 实现ApplicationContextAware接口, 注入Context到静态变量中.
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        SpringContextHolder.applicationContext = applicationContext;

        SpringContextHolder.isDebug = Objects.equals(applicationContext.getEnvironment().getProperty("debug"), Boolean.TRUE.toString());
        String serverPortStr = applicationContext.getEnvironment().getProperty("server.port");
        Optional.ofNullable(serverPortStr).ifPresent(s -> SpringContextHolder.serverPort = Integer.valueOf(s));
    }

    /**
     * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
     *
     * @param name bean名称
     * @param <T>  自动转型为所赋值对象的类型
     * @return 对象
     */
    public static <T> T getBean(String name) {
        return (T) applicationContext.getBean(name);
    }


    /**
     * 从静态变量applicationContext中取得Bean, 自动转型为所赋值对象的类型.
     *
     * @param requiredType requiredType
     * @param <T>          T
     * @return 对象
     */
    public static <T> T getBean(Class<T> requiredType) {
        return applicationContext.getBean(requiredType);
    }

    /**
     * 清除SpringContextHolder中的ApplicationContext为Null.
     */
    public static void clearHolder() {
        if (log.isDebugEnabled()) {
            log.debug("清理SpringContextHolder");
        }
        SpringContextHolder.applicationContext = null;
        SpringContextHolder.isDebug = false;
        SpringContextHolder.serverPort = null;
    }

    /**
     * 发布事件[推荐注解方式]
     *
     * @param event 事件
     */
    public static void publishEvent(ApplicationEvent event) {
        Optional.ofNullable(applicationContext).ifPresent(a -> a.publishEvent(event));
    }

    /**
     * 实现DisposableBean接口, 在Context关闭时清理静态变量.
     */
    @Override
    public void destroy() {
        SpringContextHolder.clearHolder();
    }


}
